package com.smy.baseutil.serect;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sun.misc.BASE64Decoder;

/**
 * 
* @Title: RSAUtil.java  
* @Description: RSA加解密 
* @author zhoutao    
* @date 2018年1月17日 下午5:48:32  
* @version V1.0
 */
@SuppressWarnings("restriction")
public class RSAUtil {

	private static Logger logger = LoggerFactory.getLogger(RSAUtil.class);
	
	public static final String KEY_ALGORITHM = "RSA";
	public static final String CONTENT_TYPE = "UTF-8";
	/**
	 * RSA最大加密明文大小
	 */
	private static final int MAX_ENCRYPT_BLOCK = 117;
	
    /** 
     * 签名算法 
     */  
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";  

	/**
	 * RSA最大解密密文大小
	 */
	private static final int MAX_DECRYPT_BLOCK = 128;

	private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbv/feRfESpD4NQoz"
			+ "qhmiKWi70a7c1Q/IgE26FUdCJUNGueSQQyunyLV1W2a6x3od6VpHHAlUuN01/U9yucBivtrwWT3Lb7V+0+CkBR"
			+ "zyKPsTMzZ+fzOlzQW0W2wpTwthcHUSZ4tHmN0zFRhDBuid039Ljwjz6fDpqfhUQYV+CsQIDAQAB";
	private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJu/995F8RKkPg1C"
			+ "jOqGaIpaLvRrtzVD8iATboVR0IlQ0a55JBDK6fItXVbZrrHeh3pWkccCVS43TX9T"
			+ "3K5wGK+2vBZPctvtX7T4KQFHPIo+xMzNn5/M6XNBbRbbClPC2FwdRJni0eY3TMVG"
			+ "EMG6J3Tf0uPCPPp8Omp+FRBhX4KxAgMBAAECgYAo7uLt/+PDynakdYEjgf+nnNwK"
			+ "UOTtktXnqDO7xizQafUxrZTU9P9XLqUBVmSbSqjAdlAJxYstgktT026ESeGyo40e"
			+ "CP72+7JUal7oLbfNLVJzP7URHYgipDqor5UyoFy0UKJn4dUsD7tUGP0ZjZcGsPXf"
			+ "yKmV55EtI3ZRat7fgQJBAM0NO/QQH7VMxsKlyQALNwmRg2NevQtiUgd4h5Rl2T79"
			+ "COoPkLDrp1mw0y95wsEUA5SNek110QQZRbFhtfclDLUCQQDCcshuN5LNCnyWA1w8"
			+ "urwfry0VeGbRzJErQFjnUCSVduaPu78OCMJM6Yhv/NvbOPPZxN2loIoe9xnKoLtN"
			+ "zleNAkEAwx/A2XMueTviN//C0cPaT8Sknr7cbiTVoj5T5ic1H/dxsCm3qmPVEEhv"
			+ "7lGTvl/pOEeZBnUCvT+/ThiJK/GZsQJADFV1izAxOppIrsdFyYBawHO/G1aIxxP/"
			+ "vUuWmA2IVIa3NzTEeKJrmK9TfS7/zxb8uLp5CLF3MWGhHC4300acXQJAa0AanoAb"
			+ "FclBFGpQzK3u6UvnTr7zH9UBqGgV1V3dKFKPX1kEKK6j71wU7wo3wwuLPhjXCYNO" + "Nleo6ecl2wmI9g==";

    private RSAUtil() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * <P>
     * 公钥解密
     * </p>
     *
     * @param encryptedData 已加密数据
     * @param publicKey 公钥(BASE64编码)
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {

        byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    /**
     * <P>
     * 公钥解密
     * </p>
     *
     * @param encryptedData 已加密数据
     */
    public static String decryptByPublicKey(String content) throws Exception {
        byte[] keyBytes = new BASE64Decoder().decodeBuffer(PUBLIC_KEY);
        byte[] encryptedData = Base64.decodeBase64(content);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return new String(decryptedData);
    }

    /**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     */
    public static String encryptByPrivateKey(byte[] data, String privateKey) throws Exception {

        byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return Base64.encodeBase64String(encryptedData);
    }

    /**
     * <p>
     * 私钥加密
     * </p>
     *
     * @param data 源数据
     * @param privateKey 私钥(BASE64编码)
     */
    public static String encryptByPrivateKey(String data) throws Exception {
        return encryptByPrivateKey(data.getBytes(), PRIVATE_KEY);
    }

    /**
     * 初始化密钥
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);

        KeyPair keyPair = keyPairGen.generateKeyPair();

        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        Map<String, Object> keyMap = new HashMap<>(2);

        keyMap.put("publicKey", Base64.encodeBase64String(publicKey.getEncoded()));
        keyMap.put("privateKey", Base64.encodeBase64String(privateKey.getEncoded()));
        return keyMap;
    }

    /**
     * RSA签名
     * 
     * @param content 待签名数据
     * @param privateKey 商户私钥
     * @param encode 字符集编码
     * @return 签名值
     */
    public static String sign(String content, String encode) throws Exception {
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(PRIVATE_KEY));

        KeyFactory keyf = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);

        java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);

        signature.initSign(priKey);
        signature.update(content.getBytes(encode));

        byte[] signed = signature.sign();

        return Base64.encodeBase64String(signed);
    }

    public static String sign(String content) throws Exception {

        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(PRIVATE_KEY));
        KeyFactory keyf = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);
        java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
        signature.initSign(priKey);
        signature.update(content.getBytes());
        byte[] signed = signature.sign();
        return Base64.encodeBase64String(signed);

    }

    /**
     * RSA验签名检查
     * 
     * @param content 待签名数据
     * @param sign 签名值
     * @param publicKey 分配给开发商公钥
     * @param encode 字符集编码
     * @return 布尔值
     */
    public static boolean doCheck(String content, String sign, String publicKey, String encode) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = Base64.decodeBase64(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(encode));

            boolean bverify = signature.verify(Base64.decodeBase64(sign));
            return bverify;

        } catch (Exception e) {
            logger.error("校验签名出错");
        }

        return false;
    }

    public static boolean doCheck(String content, String sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = Base64.decodeBase64(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes());

            boolean bverify = signature.verify(Base64.decodeBase64(sign));
            return bverify;

        } catch (Exception e) {
            logger.error("校验签名出错");
        }

        return false;
    }

    public static void main(String[] args) throws Exception {
        String str = "{'uid':'123456789','regist_time':'2017-12-11 17:36:58','mobile_no':'13389765641'}";
        logger.error("1231");
        // 加密
        //String sstr = encryptByPrivateKey(str);
        String sstr = "H3tGjzTCDdMr/fUPyhaUVQSXtssC1vULi/jCd1451Hlzfo7gM6d3TEzx4QNhciFAb6iXxC+/l1KTC7/DVcVXpvsdyI2MP3cSZvNe9YhHrCtUmug192tdoZYldXnwKPvFVeICN4AJHdA5qgEEVlf+XDOtBllGi7EPUAM4Yu+M+aFBu9AimYSw2hiKwg5UfkUAEIUSn62vmtcRGArC/qRok7EEsbbKxnIl40pMKXBCyvey5wNd2cW+XhbNIh0NalJv/QBL1h6reFvoYgb7UtHdRxdkw/Wa9/Vs6anyWVrXM1t+VZ4eJ/+q9ZcVXaXKZhJfByW19gQklZofu6sYFkqejw==";
        System.out.println(sstr);
        String sign = sign(str);
        System.err.println(sign);
        // 解密
        String _str = decryptByPublicKey(sstr);
        System.out.println(_str);
        System.err.println(doCheck(_str, sign, PUBLIC_KEY));

    }


}
